System.Threading.Tasks void Main() { var input = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day11.txt")).Split(',').Select(long.Parse).ToArray(); var comp = new IntCodeComputer(input.ToArray()); var robot = new Robot(0, comp); var part1 = robot.Panels.Count(); part1.Dump(); comp = new IntCodeComputer(input.ToArray()); robot = new Robot(1, comp); var minx = robot.Panels.Min(o => o.Key.Item1); var miny = robot.Panels.Min(o => o.Key.Item2); var panels = robot.Panels.ToDictionary(p => (p.Key.Item1 + Math.Abs(minx), p.Key.Item2 + Math.Abs(miny)), p => p.Value); var drawing = Enumerable.Range(0, panels.Max(p => p.Key.Item2) + 1).Select(y => new string(Enumerable.Range(0, panels.Max(p => p.Key.Item1) + 1).Select(x => panels.TryGetValue((x, y), out var p) ? (p == 1 ? '8' : '_') : '_').ToArray())).ToList(); for (int i = drawing.Count - 1; i >= 0; i--) { drawing[i].Dump(); } } class Robot { public readonly Dictionary<(int, int), int> Panels = new Dictionary<(int, int), int>(); public Robot(int startingColor, IntCodeComputer comp) { int x = 0, y = 0, heading = 0; Panels[(x, y)] = startingColor; var done = false; while (!done) { comp.Input.Enqueue(Panels.ContainsKey((x, y)) ? Panels[(x, y)] : 0); done = comp.GetNext(out var color); if (!done) { Panels[(x, y)] = (int)color; done = comp.GetNext(out var turn); if (!done) { if (turn == 0) { heading = (heading + 270) % 360; } else { heading = (heading + 90) % 360; } switch (heading) { case 0: y++; break; case 90: x++; break; case 180: y--; break; case 270: x--; break; } } } } } } class IntCodeComputer { private readonly Dictionary _mem; private long ptr = 0; private long relativebase = 0; public IntCodeComputer(long[] program) { _mem = program.Select((p, i) => new { p, i = (long)(i) }).ToDictionary(o => (long)o.i, o => (long)o.p); } public readonly Queue Input = new Queue(); public bool GetNext(out long? output) { (int[] parmModes, int opcode) op; (int[] parmModes, int opcode) readOpCode(int opCode) => (new[] { (opCode / 100) % 10, (opCode / 1000) % 10, (opCode / 10000) % 10 }, opCode % 100); long readMem(long pos) => _mem.ContainsKey(pos) ? _mem[pos] : 0; long getParmVal(int mode, long value) => mode == 0 ? readMem(value) : mode == 2 ? readMem(relativebase + value) : value; long getParm(long parm) => getParmVal(op.parmModes[parm - 1], _mem[ptr + parm]); void setParmVal(int mode, long val, long value) { if (mode == 2) _mem[relativebase + val] = value; else _mem[val] = value; } void setParm(long parm, long val) => setParmVal(op.parmModes[parm - 1], _mem[ptr + parm], val); output = default; while (_mem[ptr] != 99) { op = readOpCode((int)_mem[ptr]); switch (op.opcode) { case 1: setParm(3, getParm(1) + getParm(2)); ptr += 4; break; case 2: setParm(3, getParm(1) * getParm(2)); ptr += 4; break; case 3: if (Input.Count() == 0) return false; setParm(1, Input.Dequeue()); ptr += 2; break; case 4: output = getParm(1); ptr += 2; return false; break; case 5: ptr = getParm(1) != 0 ? getParm(2) : ptr + 3; break; case 6: ptr = getParm(1) == 0 ? getParm(2) : ptr + 3; break; case 7: setParm(3, getParm(1) < getParm(2) ? 1 : 0); ptr += 4; break; case 8: setParm(3, getParm(1) == getParm(2) ? 1 : 0); ptr += 4; break; case 9: relativebase += getParm(1); ptr += 2; break; } } return true; } }